package com.dhms.vostok1.ui.main.device

import android.annotation.SuppressLint
import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.core.content.res.ResourcesCompat
import androidx.core.view.GravityCompat
import androidx.core.view.children
import androidx.drawerlayout.widget.DrawerLayout
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.dhms.devicecenter.R
import com.dhms.devicecenter.databinding.FragmentDeviceCenterBinding
import com.dhms.uikit.SpacesItemDecoration
import com.dhms.uikit.databinding.ItemChipCategoryBinding
import com.dhms.uikit.qrCodeScan.QRCodeScanActivity
import com.dhms.vostok1.adapter.DeviceListAdapter
import com.dhms.vostok1.data.ApiState
import com.dhms.vostok1.data.TaskAndDeviceItem
import com.dhms.vostok1.data.device_center.DeviceListItemData
import com.dhms.vostok1.model.DeviceViewModel
import com.dhms.vostok1.model.DeviceViewModel.Companion.DEVICE_LIST_STATE_MAP
import com.dhms.vostok1.model.DeviceViewModel.Companion.DEVICE_STATE_RUNNING
import com.dhms.vostok1.model.DeviceViewModel.Companion.DEVICE_STATE_STOP
import com.dhms.vostok1.model.DeviceViewModel.Companion.DEVICE_STATE_UNKNOWN
import com.dhms.vostok1.model.WebSocketViewModel
import com.dhms.vostok1.network.MoshiObject
import com.dhms.vostok1.ui.main.MainActivityInterface
import com.dhms.vostok1.utils.AppFeatureManager
import com.dhms.vostok1.utils.NetworkState
import com.dhms.vostok1.utils.Utils
import com.google.android.material.chip.Chip
import com.google.zxing.client.android.Intents
import com.journeyapps.barcodescanner.ScanContract
import com.journeyapps.barcodescanner.ScanIntentResult
import com.journeyapps.barcodescanner.ScanOptions

class DeviceCenterFragment : Fragment() {

    private var _binding: FragmentDeviceCenterBinding? = null
    private val binding get() = _binding!!

    private val deviceViewModel: DeviceViewModel by activityViewModels()

    private var toSubmit: Boolean = false
    private var requestDataInfo = false

    private var deviceStatusSelected: List<Int>? = null
    private var deviceCategorySelected: List<Int>? = null

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        _binding = FragmentDeviceCenterBinding.inflate(inflater, container, false)

        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        binding.lifecycleOwner = viewLifecycleOwner

        setToolBar()

        setDeviceSearchView()

        setGetDeviceResultListener()

        setDeviceList()

        setDeviceFilterDrawer()

        WebSocketViewModel.instance.networkChange.observe(viewLifecycleOwner) {
            if (it == NetworkState.NETWORK && !requestDataInfo) {
                if (deviceViewModel.deviceListOffset == 1) {
                    deviceViewModel.getDeviceListData()
                }
                deviceViewModel.getTopLevelCategory()
                requestDataInfo = true
            }
        }
    }

    private fun setToolBar() {
        (activity as MainActivityInterface).setNotificationBadge(binding.topAppBar)
        binding.topAppBar.setOnMenuItemClickListener {
            if (WebSocketViewModel.instance.networkChange.value == NetworkState.NETWORK_NO) {
                errorTip(getString(R.string.offline_mode_unavailable))
                false
            } else {
                when (it.itemId) {
                    R.id.menu_filter -> {
                        showDeviceFilterDrawer()
                        true
                    }
                    R.id.menu_notification -> {
                        try {
                            findNavController().navigate(R.id.action_deviceCenterFragment_to_messageCenterFragment)
                        } catch (ex: Exception) {
                        }
                        true
                    }
                    R.id.menu_scanning_qr_code -> {

                        val options =
                            ScanOptions().setCaptureActivity(QRCodeScanActivity::class.java)
                        barcodeLauncher.launch(options)

                        true
                    }
                    R.id.menu_nearby_equipment -> {
                        findNavController().navigate(R.id.action_deviceCenterFragment_to_nearbyDevicesFragment)
                        true
                    }
                    else -> false
                }
            }
        }

        deviceViewModel.deviceFilters.observe(viewLifecycleOwner) {
            val iconResId =
                if (it.values.filterNotNull().isEmpty()) R.drawable.ic_filter_unset else R.drawable.ic_filter_set
            binding.topAppBar.menu.findItem(R.id.menu_filter).icon = ResourcesCompat.getDrawable(
                resources,
                iconResId,
                requireActivity().theme
            )
        }
    }

    private fun setDeviceSearchView() {
        val textChangedListener = object : TextWatcher {
            override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
            override fun afterTextChanged(s: Editable?) {}

            override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
                val name = s.toString()
                deviceViewModel.setDeviceListFilters(
                    mapOf(
                        "deName" to name.ifEmpty { null }
                    )
                )
                deviceViewModel.getDeviceListData()
            }
        }
        binding.deviceSearchView.apply {
            setOnFocusChangeListener { _, hasFocus ->
                binding.deviceSearchViewWrapper.hint = if (hasFocus) {
                    addTextChangedListener(textChangedListener)
                    null
                } else {
                    removeTextChangedListener(textChangedListener)
                    getString(R.string.device_search_placeholder)
                }
            }
        }
    }

    private fun setGetDeviceResultListener() {
        deviceViewModel.getDeviceListResult.observe(viewLifecycleOwner) {
            when (it?.state) {
                ApiState.LOADING -> {
                    (activity as MainActivityInterface).showToast(
                        message = "加载中",
                        isLoading = true,
                        timeOut = 0
                    )
                }
                ApiState.ERROR -> {
                    var tip = it.message ?: "加载失败"
                    if (WebSocketViewModel.instance.networkChange.value == NetworkState.NETWORK_NO) {
                        tip = getString(R.string.offline_mode_unavailable)
                    }
                    errorTip(tip)
                }
                else -> {
                    (activity as MainActivityInterface).hideToast()
                }
            }
        }
    }

    private val barcodeLauncher = registerForActivityResult(
        ScanContract()
    ) { result: ScanIntentResult ->
        if (result.contents == null) {
            val originalIntent = result.originalIntent
            if (originalIntent == null) {
                Log.d(TAG, "Cancelled scan")
            } else if (originalIntent.hasExtra(Intents.Scan.MISSING_CAMERA_PERMISSION)) {
                Log.d(
                    TAG,
                    "Cancelled scan due to missing camera permission"
                )
                Toast.makeText(
                    activity,
                    "请打开相机权限",
                    Toast.LENGTH_LONG
                ).show()
            }
        } else {
            Log.d(TAG, "Scanned")

            val deviceId = Utils.getQueryParameter(result.contents, Utils.deviceId)?.toLongOrNull()
            if (deviceId == null) {
                (activity as MainActivityInterface).showToast(
                    message = "获取不到设备id",
                )
                return@registerForActivityResult
            }

            (activity as MainActivityInterface).showToast(
                message = "正在获取设备信息",
                isLoading = true,
                timeOut = 15
            )

            deviceViewModel.getDeviceByDeviceId(deviceId) {
                (activity as MainActivityInterface).hideToast()
                if (it == null) {
                    (activity as MainActivityInterface).showToast(
                        message = "获取设备信息失败",
                    )
                } else {
                    deviceDetailJump(it)
                }
            }

        }
    }

    @SuppressLint("NotifyDataSetChanged")
    private fun setDeviceList() {

        binding.deviceViewModel = deviceViewModel

        binding.deviceList.adapter = DeviceListAdapter { _, index ->
            /*跳转设备中心 h5*/
            deviceViewModel.filteredDeviceListData.value?.get(index)?.let { deviceData ->
                deviceDetailJump(deviceData)
            }
        }

        binding.deviceList.addItemDecoration(
            SpacesItemDecoration(
                resources.getDimension(R.dimen.no_interval),
                resources.getDimension(com.dhms.uikit.R.dimen.list_item_divider_space)
            )
        )

        binding.deviceList.addOnScrollListener(object : RecyclerView.OnScrollListener() {
            var isSliding = true

            override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
                super.onScrollStateChanged(recyclerView, newState)
                val layoutManager = recyclerView.layoutManager as LinearLayoutManager
                if (newState == RecyclerView.SCROLL_STATE_IDLE) {
                    val lastItemPosition = layoutManager.findLastCompletelyVisibleItemPosition()
                    val itemCount = layoutManager.itemCount

                    if (lastItemPosition == (itemCount - 1) && isSliding && !deviceViewModel.isDeviceListNoMore.value!!) {
                        deviceViewModel.getDeviceListData()
                    }
                }
            }

            override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
                super.onScrolled(recyclerView, dx, dy)
                isSliding = dy > 0
            }
        })

        deviceViewModel.filteredDeviceListData.observe(viewLifecycleOwner) { it ->
            val deviceListData = it.map {
                var deviceIcon: Any? = null
                try {
                    deviceIcon =
                        if (it.deTreeChartConfig != null) MoshiObject.jsonAdapter.fromJson(it.deTreeChartConfig)
                            ?.get("icon") else null
                } catch (e: Exception) {
                    Log.e(TAG, "Icon converting failed on item: $it", e)
                }
                val deviceStatus = DEVICE_LIST_STATE_MAP[it.deShowStatus]

                TaskAndDeviceItem(
                    it.deId,
                    it.deName,
                    itemExtraInfo = it.ctName,
                    itemImgUrl = deviceIcon as String?,
                    itemStatus = deviceStatus?.get("name") as String?,
                    itemStatusColor = deviceStatus?.get("color") as Int?,
                    itemPerilSum = it.perilSum,
                    itemFaultSum = it.faultSum,
                    deHasSensor = it.deHasSensor
                )
            }
            (binding.deviceList.adapter as DeviceListAdapter).submitList(deviceListData)
            (binding.deviceList.adapter as DeviceListAdapter).notifyDataSetChanged()
        }
    }

    private fun deviceDetailJump(deviceData: DeviceListItemData) {
        deviceViewModel.setCurrentDevice(deviceData)
        deviceViewModel.clearDevicePartsData()
        val url = "${AppFeatureManager.deviceDetailUrl}?deviceId=${deviceData.deId}"
        val action =
            DeviceCenterFragmentDirections.actionDeviceCenterFragmentToWebViewFragment(url)
        findNavController().navigate(action)
    }

    private fun setDeviceFilterDrawer() {

        binding.drawerWrapper.addDrawerListener(object : DrawerLayout.DrawerListener {
            override fun onDrawerSlide(drawerView: View, slideOffset: Float) {}
            override fun onDrawerStateChanged(newState: Int) {}

            override fun onDrawerClosed(drawerView: View) {
                if (!toSubmit) {
                    binding.deviceStatusFilter.clearCheck()
                    binding.deviceCategoryFilter.clearCheck()
                    deviceStatusSelected?.forEach {
                        binding.deviceStatusFilter.check(it)
                    }
                    deviceCategorySelected?.forEach {
                        binding.deviceCategoryFilter.check(it)
                    }
                }
            }

            override fun onDrawerOpened(drawerView: View) {
                toSubmit = false

                deviceStatusSelected = binding.deviceStatusFilter.checkedChipIds
                deviceCategorySelected = binding.deviceCategoryFilter.checkedChipIds
            }
        })

        deviceViewModel.topLevelCategory.observe(viewLifecycleOwner) { topCategoryData ->
            binding.deviceCategoryFilter.removeAllViews()

            topCategoryData?.filter { (it.deviceCount ?: 0) > 0 }?.forEach { item ->
                val chip = ItemChipCategoryBinding.inflate(LayoutInflater.from(requireContext()))
                chip.chipItem.text = item.ct_name
                chip.chipItem.id = item.ct_id
                binding.deviceCategoryFilter.addView(chip.root)
            }
            val selectedDeviceCategoryId =
                deviceViewModel.deviceFilters.value?.get("deCategoryCuId")?.toString()?.toInt()
            if (selectedDeviceCategoryId != null) {
                // chipGroup.check(id) not working
                for (chip in binding.deviceCategoryFilter.children) {
                    if (chip.id == selectedDeviceCategoryId) {
                        (chip as Chip).isChecked = true
                        break
                    }
                }
            }
        }

        binding.deviceFilterSubmit.setOnClickListener {
            toSubmit = true
            val filters = mutableMapOf<String, Any?>(
                "deShowStatus" to null,
                "deCategoryCuId" to null
            )
            val deviceStatusFilter = binding.deviceStatusFilter.checkedChipIds.map {
                when (it) {
                    R.id.device_status_filter_running -> DeviceViewModel.DEVICE_STATE_RUNNING
                    R.id.device_status_filter_stop -> DeviceViewModel.DEVICE_STATE_STOP
                    else -> DeviceViewModel.DEVICE_STATE_UNKNOWN
                }
            }
            if (deviceStatusFilter.isNotEmpty()) {
                filters["deShowStatus"] = deviceStatusFilter.joinToString(",")
            }
            val deviceCategoryFilter = binding.deviceCategoryFilter.checkedChipIds
            if (deviceCategoryFilter.size != 0) {
                filters["deCategoryCuId"] = deviceCategoryFilter[0]
            }

            deviceViewModel.setDeviceListFilters(filters)
            deviceViewModel.getDeviceListData()

            binding.drawerWrapper.closeDrawer(GravityCompat.END)
        }

        binding.deviceFilterReset.setOnClickListener {
            binding.deviceStatusFilter.clearCheck()
            binding.deviceCategoryFilter.clearCheck()
        }
    }

    private fun showDeviceFilterDrawer() {
        binding.drawerWrapper.openDrawer(GravityCompat.END)
    }

    private fun errorTip(message: String?) {
        (activity as MainActivityInterface).showToast(
            R.drawable.ic_fail,
            message,
            false,
            2
        )
    }

    override fun onResume() {
        super.onResume()
        val checkedChipIds = binding.deviceStatusFilter.checkedChipIds
        when (deviceViewModel.deviceFilters.value?.get("deShowStatus")) {
            DEVICE_STATE_RUNNING.toString() -> {
                if (checkedChipIds != listOf(R.id.device_status_filter_running)) {
                    binding.deviceStatusFilter.clearCheck()
                    binding.deviceStatusFilterRunning.isChecked = true
                }
            }
            DEVICE_STATE_STOP.toString() -> {
                if (checkedChipIds != listOf(R.id.device_status_filter_stop)) {
                    binding.deviceStatusFilter.clearCheck()
                    binding.deviceStatusFilterStop.isChecked = true
                }
            }
            DEVICE_STATE_UNKNOWN.toString() -> {
                if (checkedChipIds != listOf(R.id.device_status_filter_offline)) {
                    binding.deviceStatusFilter.clearCheck()
                    binding.deviceStatusFilterOffline.isChecked = true
                }
            }
        }
    }

    companion object {
        const val TAG = "DeviceCenterFragment"
    }
}